home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-12-20 | 27.2 KB | 897 lines | [TEXT/ALFA] |
- ## -*-Tcl-*-
- # ###################################################################
- # Vince's Additions - an extension package for Alpha
- #
- # FILE: "install.tcl"
- # created: 25/7/97 {1:12:02 am}
- # last update: 20/12/97 {6:45:59 pm}
- # Author: Vince Darley
- # E-mail: <darley@fas.harvard.edu>
- # mail: Division of Engineering and Applied Sciences, Harvard University
- # Oxford Street, Cambridge MA 02138, USA
- # www: <http://www.fas.harvard.edu/~darley/>
- #
- # Copyright (c) 1997 Vince Darley
- #
- # This file contains a pretty complex package installation
- # procedure, and some more rudimentary code which queries
- # an ftp site for a list of packages and checks dates etc
- # to see if there's something new. The idea being you can
- # then just select from a menu to download and subsequently
- # install.
- #
- # Package installation:
- #
- # There is a new install mode 'Inst' which adds the Install menu.
- # Install mode is trigerred when a file's name ends in 'Install'
- # or 'INSTALL', or when the first line of the file contains the
- # letters 'install', provided in this last case, that the file
- # is not in Alpha's Tcl hierarchy. This last case is useful so
- # that a single .tcl file can be a package and be installed by
- # Alpha using these nice scripts, without the need for a separate
- # install-script-file. However once that .tcl file is installed,
- # if you open it you certainly wouldn't want it opened in Install mode!
- #
- # Once you've opened a file in install mode:
- #
- # You can select 'install this package' from the menu. (If the file's
- # first line contains 'auto-install' the menu item is automatically
- # selected, provided no modifier key is pressed). In any case, this
- # does the following: if there's an install file in the current directory
- # it is sourced. An install file is defined as a file at the same
- # level as the current file whose name matches "*install*.tcl".
- # If no install file is found, a default (but still rather
- # sophisticated) installation takes place, by calling the procedure
- # 'install::packageInstallationDialog'. Any install script in your
- # *install*.tcl file may wish to use that procedure anyway. For
- # instance, the installer for Vince's Additions uses just the
- # following lines in its installation file:
- #
- # install::packageInstallationDialog "Vince's Additions" "\
- # These additions include a number of different packages, designed to \
- # make using Alpha an even more pleasant experience! They include a \
- # more sophisticated completion and template mechanism, some bibliography \
- # conversion routines, and a general projects/documents organisation scheme."
- #
- # In any case, 'install::packageInstallationDialog' does the following:
- # It scans the current directory for files which may need installing.
- # This includes any .tcl file which is not the *install*.tcl script.
- # It also includes the same in any subdirectories of the current
- # directory. Intelligent guesses are made as to whether files are
- # Modes, Menus, Packages, Completions, Extensions, Help files or
- # UserModifications.
- #
- # Extensions are *+\d.tcl files, these go in tclExtensionsFolder
- # Modes are *Mode.tcl files, or all files in a subdir *Mode*
- # Menus are *Menu.tcl files, or all files in a subdir *Menu*
- # Completions are all files *Completions.tcl
- # Help files end in 'help' or 'tutorial' (any case)
- # UserModifications are any files in a UserModifications subdir.
- # Packages are anything else.
- #
- # UserModifications are files which a package installs once, but
- # the user is expected to edit afterwards. Hence if the package
- # is reinstalled, those files are not overwritten.
- #
- # Clearly if the original install file was in fact a .tcl file on
- # its own (with 'install' in the first line) then we don't search
- # the directory in which it sits. This is now implemented.
- #
- # ----------
- # OK, we've got all the files and worked out where they should go.
- # Now we build an installation dialog, from which the user can
- # select 'Easy Install', or 'Custom Install'. Easy install does
- # the works, custom allows the user to choose amongst all the
- # available sub-pieces. A sub-piece is any single item in the
- # install directory: so you can package up blocks of files as a single
- # package by putting them in a sub-dir.
- #
- # If you hit 'Ok' installation takes place, with optional backup
- # of removed files.
- #
- # Currently package indices and tcl indices are then rebuilt. This
- # last thing needs to be a bit more sophisticated...
- #
- # ----------
- # Caveats:
- #
- # Currently not clever enough to install, say, HTML mode in the
- # way it currently is: here we wish to install all HTML files in
- # one sub-dir of the Modes dir, but we wish to allow the user to
- # pick which sub-sets of files will go in that 'HTML and CSS modes'
- # directory. So the user could install just HTML files and ignore
- # the CSS ones. The solution I propose is to store such items in
- # separate subfolder of the base HTML subfolder. Such items would
- # then be sub-choices of the base 'install HTML mode' choice, and
- # when installed, would be installed directly into the HTML mode
- # dir.
- #
- # I think I need more feedback before embarking on further
- # modifications to this code.
- #
- # ###################################################################
- ##
-
- namespace eval install {}
- namespace eval file {}
-
- proc installMenu {} {}
- set installMenu "Install"
- set menu::items(Install) [list \
- "installThisPackage" "(-" "rebuildPackageIndices" "rebuildTclIndices"]
-
- menu::buildSome Install
-
- proc install::rebuildPackageIndices {} { alpha::rebuildPackageIndices }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "install::installThisPackage" --
- #
- # DO NOT CALL THIS PROCEDURE FROM YOUR *install.tcl INSTALLATION SCRIPT
- # IT WILL CAUSE INFINITE RECURSION AND CRASH ALPHA. THIS PROCEDURE IS
- # DESIGNED TO SOURCE YOUR *install.tcl FILE AUTOMATICALLY IF IT EXISTS.
- #
- # Instead call install::packageInstallationDialog
- # and install::askRebuildQuit
- # -------------------------------------------------------------------------
- ##
- proc install::installThisPackage {} {
- # single-file packages by definition don't have an installer.
- if {[file extension [set name [install::name]]] == ".tcl"} {
- install::packageInstallationDialog "Package"
- } else {
- set currD [file dirname $name]
- if [regexp -nocase {auto-install-script} [getText 0 [nextLineStart 0]]] {
- set installer [list $name]
- } else {
- set installer [glob -nocomplain "$currD:*nstall*.tcl"]
- if {[llength $installer] > 1} {
- alertnote "This package has two installation files. This is bad; I'll do a standard installaton."
- }
- }
-
- if {[llength $installer] == 1} {
- global installation_dir
- set installation_dir $currD
- # installer is a one-item list, so no need to wrap it
- uplevel \#0 source $installer
- unset installation_dir
- } else {
- install::packageInstallationDialog "Package"
- }
- }
- global install::forcequit
- install::askRebuildQuit ${install::forcequit}
- }
-
- proc install::sourceUpdatedSystem {} {
- global HOME install::time
- if ![info exists install::time] { return }
- foreach f [glob -nocomplain ${HOME}:Tcl:SystemCode:*.tcl] {
- if {[file tail $f] == "AlphaBits.tcl" \
- || [file tail $f] == "globals.tcl"} {continue}
- getFileInfo $f info
- if {$info(modified) > ${install::time}} {
- catch [list uplevel \#0 [list source $f]]
- }
- }
- }
-
- proc install::askRebuildQuit {{force 0}} {
- alertnote "All indices must now be rebuilt for the installation to work."
- if {![key::optionPressed] \
- || [dialog::yesno "Shall I rebuild the indices?"]} {
- install::sourceUpdatedSystem
- set n [alpha::package names]
- alpha::rebuildPackageIndices
- set new [lremove -l [alpha::package names] $n]
- if {![key::optionPressed] \
- || [dialog::yesno "Shall I rebuild the Tcl indices?"]} {
- rebuildTclIndices
- }
- auto_reset
- if [llength $new] {
- if {[dialog::yesno "You just installed the following new packages: $new; do you want to activate them at next startup?"]} {
- global package::activate modifiedVars
- eval lappend package::activate $new
- lappend modifiedVars package::activate
- }
- }
- }
- if {$force || [dialog::yesno "It is recommended that you quit and restart Alpha. Quit now?"]} {
- if {$force} {alertnote "Alpha must now quit."}
- if {[win::CurrentTail] == "Installation report"} {
- setWinInfo read-only 0
- setWinInfo dirty 1
- }
- quit
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "install::openHook" --
- #
- # Used when opening an install file to check for an 'auto-install' line.
- # -------------------------------------------------------------------------
- ##
- proc install::openHook {name} {
- if {![getModifiers] && [regexp -nocase {auto-install} [getText 0 [nextLineStart 0]]]} {
- moveWin $name 10000 10000
- global install::_name
- set install::_name $name
- catch {install::installThisPackage}
- unset install::_name
- if ![catch {bringToFront $name}] {
- killWindow
- }
- }
- }
-
- proc install::name {} {
- global install::_name
- if [info exists install::_name] {
- return ${install::_name}
- } else {
- return [win::Current]
- }
- }
-
- proc install::readAtStartup {w} {
- global alpha::readAtStartup modifiedVars
- lappend alpha::readAtStartup $w
- lappend modifiedVars alpha::readAtStartup
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "install::packageInstallationDialog" --
- #
- # Optional arguments are as follows:
- #
- # -ignore {list of files to ignore}
- # -remove {list of files to remove from Alpha hierarchy}
- # -rebuildquit '0 or 1'
- # (prompts the user to rebuild indices and quit; default 1)
- # -require {Pkg version Pkg version …}
- # e.g. -require {Alpha 6.52 elecCompletions 7.99}
- #
- # and
- #
- # -SystemCode -Modes -Menus
- # -BugFixes -Completions -Packages
- # -ExtensionsCode -UserModifications -Tools
- #
- # which force the placement of the following list of files.
- # -------------------------------------------------------------------------
- ##
- proc install::packageInstallationDialog {{pkgname "Package"} {description ""} args} {
- set win::Current [install::name]
- set currD [file dirname ${win::Current}]
- if {[file extension ${win::Current}] == ".tcl"} {
- # single file to install
- set pkgname [file root [file tail ${win::Current}]]
- set description "I'll install this single-file package, placing\
- it in its correct location in Alpha's code base."
- set rebuild [eval [list install::_packageInstallationDialog $pkgname $description \
- $currD [list [file tail ${win::Current}]]] $args]
- } else {
- set toplevels [glob -nocomplain "$currD:*.tcl"]
- eval lappend toplevels [glob -nocomplain -t TEXT "$currD:* *"]
- set toplevels [lremove -glob $toplevels *\[Ii\]nstall*]
- set toplevels [lremove -glob $toplevels *INSTALL*]
- set subdirs [glob -nocomplain "$currD:*:"]
- foreach item $toplevels {
- lappend items [file tail $item]
- }
- if [file exists $currD:Changes] {
- lappend items Changes
- }
- foreach dir $subdirs {
- lappend items "[file tail [file dirname $dir]]:"
- }
- set subdirs [lremove -glob $subdirs "*Completions:"]
- set completions [glob -nocomplain "$currD:Completions:"]
- set usermods [glob -nocomplain "$currD:UserModifications:"]
- eval [list install::_packageInstallationDialog $pkgname $description \
- $currD $items] $args
- }
- }
-
- proc install::_packageInstallationDialog {{pkgname "Package"} {description ""} currD items args} {
- global install::time
- set install::time [now]
- set install_types [list SystemCode CorePackages \
- Modes Menus BugFixes Completions Packages Home \
- ExtensionsCode UserModifications Help QuickStart Tools remove]
- set opts(-ignore) ""
- set opts(-forcequit) 0
- set opts(-require) ""
- foreach type $install_types {
- set opts(-$type) ""
- }
- getOpts [concat provide ignore require rebuildquit forcequit $install_types]
-
- foreach type $install_types {
- if {$opts(-$type) != ""} {
- eval lappend opts(-ignore) $opts(-$type)
- set $type $opts(-$type)
- }
- }
- # check if package requires others:
- array set req $opts(-require)
- foreach pkg [array names req] {
- eval package::reqInstalledVersion [list $pkg] $req($pkg)
- }
- catch {unset req}
- unset opts(-require)
- # check on -provide option
- if [info exists opts(-provide)] {
- array set prov $opts(-provide)
- foreach pkg [array names prov] {
- # check currently installed version isn't newer
- if {![catch {alpha::package versions $pkg} v]} {
- switch -- [alpha::package vcompare $v $prov($pkg)] {
- 0 {
- alertnote "Package $pkg version $v is already installed.\
- You may wish to cancel the installation."
- }
- 1 {
- alertnote "This installer is for $pkg version $prov($pkg)\
- but version $v is already installed. You may wish to\
- cancel the installation."
- }
- }
- }
- }
- catch {unset prov}
- unset opts(-provide)
- }
- # check if package has over-ridden default
- global install::forcequit
- set install::forcequit $opts(-forcequit)
- catch {unset opts(-rebuildquit)}
- unset opts(-forcequit)
- # Now assume packages/modes are sub-dirs, completions are in the
- # Completions dir, and toplevels are obvious from their name.
- # (Mode, Menu, BugFixes or default is in Packages dir)
-
- # Create a dialog:
- if {$description == ""} {
- set description "I'll do a complete installation, placing all modes,\
- menus, completions, help files, tools, extensions and packages in their\
- correct locations. In\
- addition, any core bug fixes this package contains will be patched into\
- Alpha's core Tcl code."
- }
- set y 80
- set names [list "Easy Install" "Custom Install"]
- lappend dial -n [lindex $names 0]
- eval lappend dial \
- [dialog::text "$description" 15 y 55]
- incr y 10
- eval lappend dial \
- [dialog::checkbox "Backup removed files" 1 20 y]
- eval lappend dial \
- [dialog::checkbox "Show installation log" 1 20 y]
- incr y 22
- eval lappend dial \
- [dialog::text "Click OK to continue with the installation" 15 y]
- if {${install::forcequit}} {
- eval lappend dial \
- [dialog::text "Alpha will quit after this installation." 15 y]
- }
- set othery [expr $y +10]
- lappend dial -n [lindex $names 1]
- set y 60
- eval lappend dial \
- [dialog::checkbox "Backup removed files" 1 20 y]
- eval lappend dial \
- [dialog::checkbox "Show installation log" 1 20 y]
- incr y 5
- foreach item $items {
- if {[lsearch $opts(-ignore) $item] != -1} {
- continue
- }
- if {[string match *+*.tcl $item]} {
- lappend ExtensionsCode $item
- } elseif {[regexp "SystemCode" $item]} {
- lappend SystemCode $item
- } elseif {$item == "Changes" || [string match "Writing *" $item]} {
- lappend Help $item
- } elseif {[regexp "(H|h)elp:?$" $item]} {
- lappend Help $item
- } elseif {[regexp -nocase "quick *start$" $item]} {
- lappend QuickStart $item
- } elseif {[regexp "Modes:?$" $item]} {
- lappend Modes $item
- } elseif {[regexp "Menus:?$" $item]} {
- lappend Menus $item
- } elseif {[regexp "Docs:" $item]} {
- lappend Home $item
- } elseif {[regexp "Tools" $item]} {
- lappend Tools $item
- } elseif {[regexp -nocase "mode(:|.tcl)?$" $item]} {
- lappend Modes $item
- } elseif {[regexp -nocase "menu(:|.tcl)?$" $item]} {
- lappend Menus $item
- } elseif {[regexp -nocase "bugfixes" $item]} {
- lappend BugFixes $item
- } elseif {[regexp "Completions" $item]} {
- lappend Completions $item
- } elseif {[regexp "Tools" $item]} {
- lappend Tools $item
- } elseif {[regexp "UserModifications" $item]} {
- lappend UserModifications $item
- } elseif {[regexp "CorePackages" $item]} {
- lappend CorePackages $item
- } else {
- lappend Packages $item
- }
- }
- set x 20
- set continue 0
- foreach items $install_types {
- if [info exists $items] {
- if {$continue} {
- set continue 0
- if {$y + 10 > $othery} { set othery [expr $y +10] }
- set y 100
- incr x 190
- eval lappend dial [dialog::text "continued…" $x y]
- }
- if {$items != "remove"} {
- set t "Install $items"
- } else {
- set t "Remove obsolete files"
- }
- eval lappend dial [dialog::text $t $x y]
- foreach item [set $items] {
- lappend options [list $items $item]
- regsub ":\$" $item " ƒ" item
- eval lappend dial [dialog::checkbox $item 1 [expr $x + 20] y]
- if {$y > 360} {
- set continue 1
- }
- }
- }
- }
- incr y 10
- set h [expr $othery > $y ? $othery : $y]
- set yb [expr $h - 70]
- set w [expr 390 + ($x/2)]
- set dials [list dialog -w $w -h $h]
- set y 10
- eval lappend dials [dialog::text "$pkgname installation options" 20 y 35]
- eval lappend dials [dialog::button "OK" [expr $w -80] yb]
- eval lappend dials [dialog::button "Cancel" [expr $w -80] yb]
- set res [eval [concat $dials [list -m [concat [list [lindex $names 0]] $names] 250 10 405 30] $dial]]
- if [lindex $res 1] { error "Cancel" }
- # cancel was pressed
- set easy_install [expr 1 - [lsearch $names [lindex $res 2]]]
- if $easy_install {
- set make_backup [lindex $res 3]
- set make_log [lindex $res 4]
- } else {
- set make_backup [lindex $res 5]
- set make_log [lindex $res 6]
- }
- if $make_backup {
- global HOME
- set make_backup "$HOME:InstallationBackup"
- } else {
- set make_backup ""
- }
- set i 6
- global install::_ignore install::log
- set install::_ignore $opts(-ignore)
- set install::log ""
- foreach o $options {
- incr i
- if {!$easy_install && ![lindex $res $i]} { continue }
- set type [lindex $o 0]
- set name [lindex $o 1]
- message "Installing $type '$name'"
- install::files $type $currD $name $make_backup
- }
- unset install::_ignore
- if $make_log {
- install::showLog
- } else {
- unset install::log
- }
- }
-
- proc install::showLog {{title "Installation report"}} {
- global install::log
- new -g 0 160 640 300 -n $title
- if {${install::log} == ""} {
- insertText "No changes were made. You must have already installed this package."
- } else {
- insertText ${install::log}
- insertText "End of report."
- }
- goto 0
- winReadOnly
- unset install::log
- }
-
- proc userMessage {{alerts 1} {message ""}} {
- if $alerts {
- alertnote $message
- } else {
- message $message
- }
- }
-
- proc file::standardFind {f} {
- global HOME auto_path PREFS tclExtensionsFolder
- set dirs $auto_path
- lappend dirs $HOME:Tcl:Completions $PREFS $HOME:Help $HOME:Tools
- if [info exists tclExtensionsFolder] { lappend dirs $tclExtensionsFolder }
- foreach dir $dirs {
- if [file exists "${dir}:${f}"] {
- return "${dir}:${f}"
- }
- }
- if [regexp : $f] {
- foreach dir $dirs {
- if [file exists "[file dirname ${dir}]:${f}"] {
- return "[file dirname ${dir}]:${f}"
- }
- }
- }
- error "Not found"
- }
-
-
- # Install 'name' from $currD into where it should go
- # If 'name' ends in a colon, it's a directory. We can just
- # use glob to get a list!
- proc install::files {type from name backup} {
- global HOME PREFS tclExtensionsFolder
- set flist [glob -nocomplain $from:$name*]
- switch -- $type {
- Tools {
- set to "${HOME}:Tools"
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- remove {
- if ![catch {file::standardFind $name} what] {
- if {[regexp {:$} $name]} {
- foreach f [glob -nocomplain ${what}*] {
- file::removeOne $f $backup
- }
- install::log "Removed dir: $name"
- rmdir $what
- } else {
- file::removeOne $what $backup
- }
- }
- }
- SystemCode -
- Modes -
- Menus -
- Packages {
- set to "${HOME}:Tcl:${type}"
- if {[regexp {:$} $name] && $name != "${type}:"} {
- install::file_to $name $to
- append to ":[file dirname $name]"
- }
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- CorePackages {
- set to "${HOME}:Tcl:SystemCode:CorePackages"
- if {[regexp {:$} $name] && $name != "${type}:"} {
- install::file_to $name $to
- append to ":[file dirname $name]"
- }
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- QuickStart {
- set to "${HOME}:QuickStart"
- foreach f $flist {
- install::file_to $f $to $backup
- install::readAtStartup "${HOME}:QuickStart:[file tail $f]"
- }
- }
- Home {
- set to "${HOME}"
- if {[regexp {:$} $name] && $name != "${type}:"} {
- install::file_to $name $to
- append to ":[file dirname $name]"
- }
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- Help {
- set to "${HOME}:Help"
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- BugFixes {
- foreach f $flist {
- procs::patchOriginalsFromFile $f 0
- install::log "Installed patches from $f"
- }
- }
- Completions {
- set to "${HOME}:Tcl:Completions"
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- UserModifications {
- set to "${HOME}:Tcl:UserModifications"
- global install::noreplace
- set install::noreplace 1
- foreach f $flist {
- install::file_to $f $to $backup
- }
- set install::noreplace 0
- }
- ExtensionsCode {
- if ![info exists tclExtensionsFolder] {
- set tclExtensionsFolder $PREFS
- alertnote "This installation contains extension\
- (+.tcl) files. These require\
- the 'Smarter Source' package, which you do not have\
- installed. I've put the extension\
- files in your prefs directory, but they will not operate\
- without that package."
- }
- set to "$tclExtensionsFolder"
- foreach f $flist {
- install::file_to $f $to $backup
- }
- }
- }
- message "File installation complete"
- }
-
- proc install::log {text} {
- global install::log
- append install::log "${text}\r"
- }
-
- proc install::file_to {file to {backup ""}} {
- if {[regexp -nocase {(help|tutorial)$} [file tail $file]] \
- || ([file tail $file] == "Changes")} {
- global HOME
- install::_file_to $file "$HOME:Help" $backup
- } elseif [regexp {\+\d*.tcl} [file tail $file]] {
- global tclExtensionsFolder PREFS
- if ![info exists tclExtensionsFolder] { set tclExtensionsFolder $PREFS }
- install::_file_to $file $tclExtensionsFolder $backup
- } else {
- if {[file isdirectory $file]} {
- set to "${to}:[file tail $file]"
- if ![file exists $to] {mkdir $to}
- foreach f [glob "$file:*"] {
- install::file_to $f $to $backup
- }
- } else {
- install::_file_to $file $to $backup
- }
- }
- }
-
- proc install::_file_to {file to {backup ""}} {
- global install::_ignore
- foreach suffix ${install::_ignore} {
- if [string match *${suffix} $file] { return }
- }
- message "Installing [file tail $file]"
- if [file::ensureDirExists $to] {
- install::log "Created dir '$to'"
- }
- if [regexp {:$} $file] {
- # Install a directory
- if [file::ensureDirExists "${to}:[file tail [file dirname $file]]"] {
- install::log "Created dir '${to}:[file tail [file dirname $file]]'"
- }
- return
- }
- set files [glob -nocomplain "${file}*"]
- global install::noreplace
- if {[info exists install::noreplace] && ${install::noreplace}} {
- foreach ff $files {
- foreach suffix ${install::_ignore} {
- if [string match *${suffix} $file] { continue }
- }
- set f [file tail $ff]
- if ![file exists "${to}:$f"] {
- if [file exists "$ff" ] {
- cp "$ff" "${to}:$f"
- install::log "copied '[file tail $ff]' to '${to}:$f'"
- }
- }
- }
- } else {
- foreach ff $files {
- foreach suffix ${install::_ignore} {
- if [string match *${suffix} $file] { continue }
- }
- set f [file tail $ff]
- # check if files are actually different before removing
- if [file exists "$ff" ] {
- if [file exists ${to}:$f] {
- if {[regexp "tclIndexx?" [file tail $f]] || \
- [file::sameModifiedDate $ff ${to}:$f]} {
- continue
- }
- file::remove $to [list $f] $backup
- }
- cp "$ff" "${to}:$f"
- install::log "copied '[file tail $ff]' to '${to}:$f'"
- } else {
- alertnote "Installation file $f does not exist!"
- }
- }
- }
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "file::hyperOpen" --
- #
- # Called by embedded hyperlinks; we look through an installation
- # directory (and subdirs) if it is known, then the prefs directory,
- # then all of the auto_path. If the file is of type TEXT, we open
- # it, else we ask the finder to open it.
- # -------------------------------------------------------------------------
- ##
- proc file::hyperOpen { name } {
- global PREFS tclExtensionsFolder auto_path
- set currD [list [file dirname [win::Current]]]
- set dirs [glob -nocomplain "$currD:*:"]
- foreach d $dirs {
- lappend currD [string trimright $d :]
- }
- lappend currD $PREFS
- if [info exists tclExtensionsFolder] { lappend currD $tclExtensionsFolder }
- foreach d [concat $currD $auto_path] {
- if [file exists "$d:$name" ] {
- file::openAny "$d:$name"
- return
- }
- }
- beep
- message "Sorry, couldn't find $name"
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "file::hyperHelpOpen" --
- #
- # Called by embedded hyperlinks; we look through an installation
- # directory (and subdirs) if it is known, then the prefs directory,
- # then all of the auto_path.
- # -------------------------------------------------------------------------
- ##
- proc file::hyperHelpOpen { name } {
- global HOME auto_path
- set currD [list [file dirname [win::Current]]]
- set dirs [glob -nocomplain "$currD:*:"]
- foreach d $dirs {
- lappend currD [string trimright $d :]
- }
- lappend currD $HOME:Help
- foreach d [concat $currD $auto_path] {
- set ns [glob -nocomplain "$d:${name}*"]
- foreach n $ns {
- if [regexp -nocase "help" [file tail $n]] {
- edit $n
- return
- }
- }
- }
- beep
- message "Sorry, couldn't find a help file for $name"
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "file::jumpToCode" --
- #
- # It creates a hyperlink to a specific string in a code file, without
- # requiring a mark to be defined there. It was handy for identifying places
- # in other packages that potentially collide with my key-bindings.
- #
- # Author: Jon Guyer.
- # -------------------------------------------------------------------------
- ##
- proc file::jumpToCode {text file code} {
- set hyper {edit -c }
- append hyper $file
- append hyper { ; set pos [search -f 1 -r 1 "}
- append hyper $code
- append hyper {"] ; select [lindex $pos 0] [lindex $pos 1]}
- file::searchAndHyperise $text $hyper 0 3
- }
-
-
- proc file::sameModifiedDate {a b} {
- getFileInfo $a infoa
- getFileInfo $b infob
- # bigger = newer
- set ma $infoa(modified)
- set mb $infob(modified)
- return [expr $ma == $mb ? 1 : 0]
- }
-
- proc file::secondIsOlder {a b} {
- getFileInfo [stripNameCount $a] infoa
- getFileInfo [stripNameCount $b] infob
- # bigger = newer
- set ma $infoa(modified)
- set mb $infob(modified)
- return [expr $ma > $mb ? 1 : 0]
- }
-
- proc file::replaceSecondIfOlder {a b} {
- if ![file exists $a] { error "First does not exist!" }
- if ![file exists $b] { error "Second does not exist!" }
- if [file::secondIsOlder $a $b] {
- set open [file::removeCheckingWins $b]
- cp $a $b
- install::log "Copied [file tail $a] to $b"
- if $open {
- openFileQuietly $b
- }
- return 1
- } elseif [file::secondIsOlder $b $a] {
- install::log "The pre-existing [file tail $a] is newer than the one which was to be installed."
- }
- return 0
- }
-
- proc file::removeCheckingWins {f} {
- install::log "Removed $f"
- if {[set i [lsearch -regexp [winNames -f] "^[quote::Regfind $f]( <\d+>)?$"]] != -1} {
- bringToFront [lindex [winNames -f] $i]
- killWindow
- removeFile $f
- return 1
- }
- removeFile $f
- return 0
- }
-
- proc file::remove {to files {backup ""}} {
- foreach f $files {
- if [file exists "${to}:$f" ] {
- file::removeOne "${to}:$f" $backup
- }
- }
- }
-
- proc file::removeOne {f {backup ""}} {
- set ff [file tail $f]
- message "Removing old '$ff'"
- if {${backup} != ""} {
- if ![file exists $backup] { mkdir $backup }
- set i ""
- while {[file exists ${backup}:$ff$i]} {
- if {$i == ""} { set i 0}
- incr i
- }
- cp $f ${backup}:$ff$i
- }
- file::removeCheckingWins $f
- }
-
-